//
//  View+CBS.swift
//  TTCOM
//
//  Created by Toj on 4/20/23.
//

// NOTE: CBS = corner + border + shadow

import UIKit

private var runtime_corner_layer_key = "corner_layer_key"

public extension TTView {
    
    var st_cornerRadius: CGFloat {
        set { cm_cornerRadius = newValue }
        get { return cm_cornerRadius }
    }
    
    var cm_cornerRadius: CGFloat {
        set {
            let corners: CACornerMask =
            [
                .layerMinXMinYCorner,
                .layerMaxXMinYCorner,
                .layerMinXMaxYCorner,
                .layerMaxXMaxYCorner
            ]
            cm_corner(radius: newValue, corners: corners)
        }
        get { return layer.cornerRadius }
    }
    
    /**
     设置圆角
     -  CACornerMask
     -      layerminxminycorner 顶部左侧 的圆角 -> 左上角
     -      layermaxxminycorner 顶部右侧 的圆角 -> 右上角
     -      layerminxmaxycorner 底部左侧 的圆角 -> 左下角
     -      layerMaxXMaxYCorner 底部右侧 的圆角 -> 右下角
     */
    func cm_corner(
        radius: CGFloat,
        corners: CACornerMask
    ) {
        layer.cornerRadius = radius
        layer.maskedCorners = corners
        clipsToBounds = true
    }
    
    func cm_corner(
        shape sframe: CGRect = .zero,
        radius: CGSize = .zero,
        corners: UIRectCorner = .allCorners
    ) {
        let path = UIBezierPath(roundedRect: bounds, byRoundingCorners: corners, cornerRadii: radius)
        let shapeLayer = CAShapeLayer()
        let shapeFrame = sframe == .zero ? bounds : sframe
        shapeLayer.frame = shapeFrame
        shapeLayer.path = path.cgPath
        layer.mask = shapeLayer
    }
    
    var st_borderColor: TTColor? {
        set { cm_borderColor = newValue }
        get { return cm_borderColor }
    }
    
    var cm_borderColor: TTColor? {
        set {
            guard let color = newValue else { return }
            cm_border(color: color)
        }
        get {
            guard let color = layer.borderColor else { return nil }
            return UIColor(cgColor: color)
        }
    }
    
    /** 边框 */
    var st_borderWidth: CGFloat {
        set { layer.borderWidth = newValue }
        get { return layer.borderWidth }
    }
    
    /** 边框 */
    func st_border(
        color: TTColor,
        width: CGFloat = 1
    ) {
        /** 宽度 */
        layer.borderWidth = width
        /** 颜色 */
        layer.borderColor = color.cgColor
    }
    
    /** 边框 */
    func cm_border(
        color: TTColor,
        width: CGFloat = 1
    ) {
        /** 宽度 */
        layer.borderWidth = width
        /** 颜色 */
        layer.borderColor = color.cgColor
    }
    
    /**
     设置阴影
     - NOTE: 会触发离屏渲染, 不需要提前设置 视图大小
     */
    func cm_shadow(
        color: UIColor = UIColor.black.st_alpha(0.3),
        opacity: Float = 0.15,
        radius: CGFloat = 2,
        offset: CGSize = CGSize(width: 0, height: -2),
        corner cradius: CGFloat = 0
    ) {
        layer.masksToBounds = false
        layer.shadowColor = color.cgColor
        layer.shadowOpacity = opacity
        layer.shadowRadius = radius
        layer.shadowOffset = offset
        if cradius == 0 { return }
        layer.cornerRadius = cradius
    }
    
    /**
     设置阴影
     - NOTE: 不会触发离屏渲染, 但是得需要提前设置 视图大小
     */
    func st_shadow(
        color: UIColor = UIColor.black.st_alpha(0.3),
        opacity: Float = 0.5,
        radius: CGFloat = 2,
        offset: CGSize = CGSize(width: 0, height: -2),
        corner cradius: CGFloat = 0
    ) {
        layer.shadowColor = color.cgColor
        layer.shadowOpacity = opacity
        layer.shadowRadius = radius
        // width: 水平方向, height: 垂直方向
        layer.shadowOffset = offset
        
        layer.cornerRadius = cradius
        let path = UIBezierPath(roundedRect: bounds, cornerRadius: cradius)
        layer.shadowPath = path.cgPath
        
        guard cradius > 0 else {
            st_removeCorner()
            return
        }
        
        let associatedValue = objc_getAssociatedObject(self, &runtime_corner_layer_key)
        let conerLayer = (associatedValue as? CALayer) ?? CALayer()
        conerLayer.frame = bounds
        conerLayer.backgroundColor = backgroundColor?.cgColor
        conerLayer.cornerRadius = cradius
        layer.insertSublayer(conerLayer, at: 0)
        backgroundColor = .clear
        guard associatedValue == nil else { return }
        objc_setAssociatedObject(
            self, &runtime_corner_layer_key,
            conerLayer, .OBJC_ASSOCIATION_RETAIN_NONATOMIC
        )
    }
    
    /**
     设置圆角
     - NOTE: 不会触发离屏渲染, 但是得需要提前设置 视图大小
     */
    func st_corner(
        cradius: CGFloat = 1,
        shadow scolor: UIColor? = nil,
        sopacity: Float = 0,
        sradius: CGFloat = 0,
        soffset: CGSize = .zero
    ) {
        if cradius > 0 {
            let associatedValue = objc_getAssociatedObject(self, &runtime_corner_layer_key)
            let conerLayer = (associatedValue as? CALayer) ?? CALayer()
            conerLayer.frame = bounds
            conerLayer.backgroundColor = backgroundColor?.cgColor
            conerLayer.cornerRadius = cradius
            layer.insertSublayer(conerLayer, at: 0)
            backgroundColor = .clear
            if associatedValue == nil {
                objc_setAssociatedObject(
                    self, &runtime_corner_layer_key,
                    conerLayer, .OBJC_ASSOCIATION_RETAIN_NONATOMIC
                )
            }
        }
        else {
            st_removeCorner()
        }
        
        guard let color = scolor else { return }
        layer.shadowColor = color.cgColor
        layer.shadowOpacity = sopacity
        layer.shadowRadius = sradius
        // width: 水平方向, height: 垂直方向
        layer.shadowOffset = soffset
        layer.cornerRadius = cradius
        
        let path = UIBezierPath(roundedRect: bounds, cornerRadius: cradius)
        layer.shadowPath = path.cgPath
    }
    
    /**
     移除渐变色
     */
    func st_removeCorner() {
        // 查看是否有缓存值
        guard let associatedObjectValue = objc_getAssociatedObject(self, &runtime_corner_layer_key),
              let contentsLayer = associatedObjectValue as? CALayer else { return }
        contentsLayer.removeFromSuperlayer()
        
        // 清除对象内部值
        objc_setAssociatedObject(
            self, &runtime_corner_layer_key,
            nil, .OBJC_ASSOCIATION_RETAIN_NONATOMIC
        )
    }
}
